package com.sz.common.core.service;

import com.sz.common.base.utils.BeanUtils;
import com.sz.common.core.service.role.RoleMembership;
import com.sz.common.core.system.entity.Permission;
import com.sz.common.core.system.entity.Role;
import com.sz.common.core.system.service.AuthorizationService;
import com.sz.common.core.system.service.PermissionService;
import com.sz.common.core.system.service.RoleService;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Function: AbstractPrincipal <br>
 * Author: Charles <br>
 * Date: 2017-01-20 16:53:00
 */
public abstract class AbstractPrincipal implements Principal {

    protected int domainId;
    protected int accountId;
    protected String accountName;
    protected String friendlyName;
    protected String ipAddr;
    protected String preferredLanguage;

    protected int associatedAccountId;
    protected String associatedAccountName;

    protected Map<Integer, String> roles = new HashMap<>();
    protected Map<Integer, String> permissions = new HashMap<>();


    protected transient PrincipalListener listener;

    @Override
    public void setListener(PrincipalListener listener) {
        this.listener = listener;
    }

    /**
     * @param domainId    域Id
     * @param accountId   账户Id，可能为运营账户，或者供应商，或者客户
     * @param accountName 账户登录名，可能运营账户，或者供应商，或者客户
     */
    public AbstractPrincipal(int domainId, int accountId, String accountName) {
        if (domainId == 0 || accountId < 0 || accountName == null || accountName.trim().length() == 0) {
            throw new IllegalArgumentException();
        }
        this.domainId = domainId;
        this.accountId = accountId;
        this.accountName = accountName;
    }

    @Override
    public int getDomainId() {
        return domainId;
    }

    @Override
    public String getAccountName() {
        return accountName;
    }

    @Override
    public void setAccountName(String name) {
        this.accountName = name;
    }

    @Override
    public int getAccountId() {
        return accountId;
    }

    @Override
    public String getFriendlyName() {
        return friendlyName;
    }

    @Override
    public void setFriendlyName(String friendlyName) {
        this.friendlyName = friendlyName;
    }

    @Override
    public String getIpAddr() {
        return ipAddr;
    }

    @Override
    public void setIpAddr(String ipAddr) {
        this.ipAddr = ipAddr;
        principalUpdated();
    }

    /**
     * @see Principal#setPreferredLanguage(String)
     */
    @Override
    public void setPreferredLanguage(String language) {
        this.preferredLanguage = language;
        principalUpdated();
    }

    @Override
    public String getPreferredLanguage() {
        return this.preferredLanguage;
    }

    @Override
    public int getAssociatedAccountId() {
        return associatedAccountId;
    }

    @Override
    public void setAssociatedAccountId(int associatedAccountId) {
        this.associatedAccountId = associatedAccountId;
    }

    @Override
    public String getAssociatedAccountName() {
        return associatedAccountName;
    }

    @Override
    public void setAssociatedAccountName(String associatedAccountName) {
        this.associatedAccountName = associatedAccountName;
    }

    @Override
    public void refreshRoles() {
        this.roles.clear();
        this.permissions.clear();
    }

    @Override
    public List<Integer> getRoleIds() {
        List<Integer> list = new ArrayList<>();
        if (this.roles.size() == 0) {
            synchronized (AbstractPrincipal.class) {
                if (this.roles.size() == 0) {
                    loadRoles();
                }
            }
        }
        this.roles.keySet().forEach(id -> list.add(id));
        return list;
    }

    /**
     * 获取角色code列表.
     *
     * @return 角色code列表
     */
    @Override
    public List<String> getRoles() {
        List<String> list = new ArrayList<>();
        if (this.roles.size() == 0) {
            synchronized (AbstractPrincipal.class) {
                if (this.roles.size() == 0) {
                    loadRoles();
                }
            }
        }
        this.roles.values().forEach(roleCode -> list.add(roleCode));
        return list;
    }

    /**
     * @return 权限Id列表
     */
    @Override
    public List<Integer> getPermissionIds() {
        List<Integer> list = new ArrayList<>();
        if (this.permissions.size() == 0) {
            synchronized (AbstractPrincipal.class) {
                if (this.permissions.size() == 0) {
                    loadPermissions();
                }
            }
        }
        this.permissions.keySet().forEach(id -> list.add(id));
        return list;
    }

    @Override
    public List<String> getPermissions() {
        List<String> list = new ArrayList<>();
        if (this.permissions.size() == 0) {
            synchronized (AbstractPrincipal.class) {
                if (this.permissions.size() == 0) {
                    loadPermissions();
                }
            }
        }
        this.permissions.values().forEach(code -> list.add(code));
        return list;
    }

    @Override
    public void refreshPermissions() {
        this.permissions.clear();
    }

    protected void loadRoles() {
        try {
            RoleService roleService = BeanUtils.getBean(RoleService.class);
            List<Role> rolesList = roleService.getRoleByMember(
                    new RoleMembership(this.accountId, this.getMembershipType()));
            if (rolesList != null && rolesList.size() > 0) {
                rolesList.forEach(role -> roles.put(role.getId(), role.getCode()));
            }
            principalUpdated();
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    protected void loadPermissions() {
        if (this.isRoot()) { //ROOT has all permissions by default
            return;
        }
        // 获取角色id集合
        List<Integer> roleIds = this.getRoleIds();

        // 从授权表（authorization）中获取权限id集合
        AuthorizationService authorizationService = BeanUtils.getBean(AuthorizationService.class);
        List<Integer> permissionIds = authorizationService.findPermissionIdsByRoleIds(roleIds, 2);
        // 获取权限对象集合
        PermissionService permissionService = BeanUtils.getBean(PermissionService.class);
        List<Permission> permissionList = permissionService.findPermissionListByIds(permissionIds);
        if (permissionList != null) {
            permissionList.forEach(
                    permission -> permissions.put(permission.getId(), permission.getCode()));
        }
        principalUpdated();
    }

    /**
     *
     */
    protected void principalUpdated() {
        if (this.listener != null) {
            this.listener.principalUpdated(this);
        }
    }

    /**
     * @return
     */
    @Override
    public boolean isAnonymous() {
        return this.accountId == 0;
    }

}
